#include <iostream>
#include <string>
#include <map>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include "dir.h"
#include "bookdescr.h"

using namespace std;

void print_tree(IDir *pdir, int ident);
bool read_book_descr(IFile *pif, CBookDescr &bd);

map<string, CBookDescr> myLib; // path -> BookDescr

int main(int, char**) {

//  xmlAddEncodingAlias("ISO-8859-5", "windows-1251");

  IDir *pid = dynamic_cast<IDir*>(filesystem.Create("/home/lazyfrog-nb-ubuntu/books/"));
  if (NULL != pid) 
    print_tree(pid, 0);
  else
    cout << "something wrong" << endl;

  xmlCleanupParser();

  xmlMemoryDump();

  cout << "myLib.size() == " << myLib.size() << endl;

  map<string, CBookDescr>::const_iterator cit = myLib.begin();
  while (myLib.end() != cit) {
    cout << "---=== " << cit->first << " ===---" << endl;    
    std::multimap<std::string, std::string>::const_iterator fit = cit->second.fields.begin();
    while (cit->second.fields.end() != fit) {
      cout << fit->first << " = \"" << fit->second << "\"" << endl;
      fit++;
    }

    cout << endl;
    cit++;
  }

  return 0;
}

void print_lines(ITextFile *pitf, int ident) {
  ITextFile::lines_iterator it = pitf->begin();
  int j = 0;
  while (j < 3 && pitf->end() != it) {
    cout << ">";
    for (int i = 0; i < ident; ++i) cout << " ";
    cout << *it << endl;
    j++;
    it++;
  }
  
}

void print_tree(IDir *pdir, int ident) {
  IDir::iterator it = pdir->begin();
  
  while (pdir->end() != it) {
    for (int i = 0; i < ident; ++i) cout << " ";

    INamed *pin = dynamic_cast<INamed*>(*it);
    string name;
    if (NULL != pin) {
      cout << pin << pin->Name() << endl;
      name = pin->Name();
    } else {
      char buff[64];
      sprintf(buff, "%d", *it);
      name = buff;
      cout << pin << " -- no name -- \t" << name << endl;
    }

    IDir *pid = dynamic_cast<IDir*>(*it);
    if (NULL != pid) 
      print_tree(pid, ident + 1);

    IFile *pif = dynamic_cast<IFile*>(*it);
    if (NULL != pif) {
      CBookDescr bd;
      if (read_book_descr(pif, bd)) {
        cerr << name << " oook" << endl;
        while (myLib.end() != myLib.find(name)) name = name + " x";
        myLib[name] = bd;
      } else {
        cerr << "problems with reading " << name << endl;
      }
      cerr << name << " OK" << endl;
    }

/*    ITextFile *pitf = dynamic_cast<ITextFile*>(*it);
    if (NULL != pitf)
      print_lines(pitf, ident + 2); */

    it++;
  }
}

xmlNode* findXPath(xmlNode *pRoot, const char* pchXPath) {
  size_t slash_pos = string(pchXPath+1).find('/');
  string tag = string(pchXPath).substr(1, slash_pos);

  cerr << "-> findXPath(" << pRoot->name << ", " << pchXPath << ") - tag is " << tag << endl;
  
  xmlNode *p = pRoot;
  while (NULL != p) {
    if (tag == (const char*)p->name) {
      if (string::npos == slash_pos) {
        cerr << "! found !" << p << endl;
        return p;
      }
      else
        return findXPath(p->children, pchXPath + slash_pos + 1);
    }

    p = p->next;
  }

  return p;
}

bool read_book_descr(IFile *pif, CBookDescr &bd) {
  cerr << "-> read_book_descr" << endl;
  //xmlParserCtxtPtr ctxt;
//  ctxt = xmlNewParserCtxt();
  cout << "reading file with size = " << pif->size() << endl;
  //ctxt = xmlCreateDocParserCtxt((const xmlChar*)pif->read());
  //if (ctxt->encoding != NULL)
  //  cerr << ctxt->encoding << endl;
  //if (NULL == ctxt)
  //  cerr << "ctxt is NULL" << endl;
  //xmlCharEncoding e = xmlDetectCharEncoding((const unsigned char*)pif->read(), pif->size());
  //xmlParseCharEncoding((const char*)pif->read());
  //cerr << "e == " << e << endl;
 
//  xmlDocPtr pdoc = xmlCtxtReadDoc(ctxt, (const xmlChar*)pif->read(), "http://localhost", XML_CHAR_ENCODING_8859_5, 0);

  xmlDocPtr pdoc = xmlReadMemory((const char*)pif->read(), pif->size(), "noname.xml", NULL /*"windows-1251"*/ /*"ISO-8859-5"*/, 0);
  //cout << "reading file with size = " << pif->size() << endl;
  pif->free();
  if (NULL == pdoc) {
    cerr << "can't read doc" << endl;
    //if (ctxt->encoding != NULL)
    //  cerr << ctxt->encoding << endl;
    
    //cerr << "-" << endl;
    //cerr << (const char*)pif->read() << endl;
    //cerr << "-" << endl;
    return false;
  }
  cerr << "---" << endl;
  xmlNodePtr pRoot = xmlDocGetRootElement(pdoc);

  if (NULL == pRoot) return false;
  xmlNodePtr pNode = findXPath(pRoot, "/FictionBook/description/title-info/author/last-name");
  //cerr << "N: " << pNode->children->content << endl;
  string Author;
  if (NULL != pNode && NULL != pNode->children && NULL != pNode->children->content) {
    //cerr << "L: " << pNode->name << endl;
    Author = (const char*)pNode->children->content;
    //Author += " ";
  }
  pNode = findXPath(pRoot, "/FictionBook/description/title-info/author/first-name");
  if (NULL != pNode && NULL != pNode->children && NULL != pNode->children->content) {
    Author += " ";
    Author += (const char*)pNode->children->content;
  }

  pNode = findXPath(pRoot, "/FictionBook/description/title-info/book-title");
  string Title;
  if (NULL != pNode && NULL != pNode->children && NULL != pNode->children->content)
    Title = (const char*)pNode->children->content;

  bd.fields.insert(pair<string, string>("Author", Author));
  bd.fields.insert(pair<string, string>("Title", Title)); 
 
  xmlFreeDoc(pdoc);

  cerr << "<- read_book_descr" << endl; 
  return true;
}

// Сценарии чтения файлов:
// 1. перебор файлов в папке
//    - нашли очередной файл
//    - прочитали целиком
//    - извлекли поля
//    - сохранили поля в базе
//    - взяли следующий файл
//
// 2. поиск конкретного файла
//    - по заданному пути ищем ближайший контейнер
//    - открываем контейнер, ищем в нём 
//    - читаем и т.д.
